package com.ssm.basis.service.util;

import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.springframework.util.ClassUtils.ARRAY_SUFFIX;

public abstract class ReflectionUtil extends ReflectionUtils {
    /**
     * 设置对象属性
     *
     * @param instance  实例对象或 Class 对象
     * @param fieldName 成员变量名
     * @param value     值
     */
    public static void setPrivateField(Object instance, String fieldName, Object value) {
        Field field = findField(getClass(instance), fieldName);
        Assert.notNull(field, "object " + fieldName + " field is null");
        makeAccessible(field);
        setField(field, instance, value);
    }

    /**
     * 寻找对象有参方法
     *
     * @param instance       实例对象
     * @param methodName     方法名
     * @param parameterTypes 方法参数类型
     */
    public static Method findMethod(Object instance, String methodName, Class<?>... parameterTypes) {
        return findMethod(getClass(instance), methodName, parameterTypes);
    }

    /**
     * 寻找对象无参方法
     *
     * @param instance   实例对象
     * @param methodName 方法名
     */
    public static Method findMethod(Object instance, String methodName) {
        return findMethod(getClass(instance), methodName);
    }

    /**
     * 将方法设置为可访问，并调用该方法
     *
     * @param instance 实例对象
     * @param method   方法对象
     * @param args     方法入参
     */
    public static Object invokePrivateMethod(Object instance, Method method, Object... args) {
        makeAccessible(method);
        return invokeMethod(method, getClass(instance), args);
    }

    /**
     * 获取类的所有属性，包括父类
     */
    public static List<Field> getAllField(Object object) {
        Class<?> clazz = getClass(object);
        Method getDeclaredFields = findMethod(ReflectionUtils.class, "getDeclaredFields", Class.class);
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            // 获取类的所有属性，带缓存
            Field[] fields = (Field[]) invokePrivateMethod(ReflectionUtils.class, getDeclaredFields, clazz);
            fieldList.addAll(Arrays.asList(fields));
            // 获取父类
            clazz = clazz.getSuperclass();
        }
        return fieldList;
    }

    /**
     * 获取类上的所有注解，包括父类
     */
    public static List<Annotation> getAllAnnotation(Object object) {
        Class<?> clazz = getClass(object);
        List<Annotation> annotationList = new ArrayList<>();
        while (clazz != null) {
            annotationList.addAll(Arrays.asList(clazz.getAnnotations()));
            // 获取父类
            clazz = clazz.getSuperclass();
        }
        return annotationList;
    }

    private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
    private static final String INTERNAL_ARRAY_PREFIX = "[";

    /**
     * 获取类的包名
     */
    public static String getPackageName(Class<?> clazz) {
        String name = clazz.getName();

        // "java.lang.String[]" style arrays
        if (name.endsWith(ARRAY_SUFFIX)) {
            name = name.substring(0, name.length() - ARRAY_SUFFIX.length());
        }

        // "[Ljava.lang.String;" style arrays
        if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
            name = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
        }

        // "[[I" or "[[Ljava.lang.String;" style arrays
        if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
            name = name.substring(INTERNAL_ARRAY_PREFIX.length());
        }

        return name;
    }

    /**
     * 获取 Class 对象
     */
    static Class<?> getClass(Object object) {
        return object instanceof Class ? (Class<?>) object : object.getClass();
    }
}